/*
 * @Author: zhengzhiwei
 * @Description: 绘制组织机构图
 */

import { Graph, Node } from '@antv/x6'
import dagre from 'dagre'

class DBX6 {
  //  * 绘制图形
  //  * @param dom dom容器
  //  * @param data 数据源
  //  */
  init(dom: any, data: any) {
    Graph.registerEdge(
      // 自定义边
      'org-edge',
      {
        zIndex: -1,
        attrs: {
          line: {
            strokeWidth: 2,
            stroke: '#A2B1C3',
            sourceMarker: null,
            targetMarker: null,
          },
        },
      },
      true
    )

    // 布局方向
    const dir: unknown = 'BT' // LR RL TB BT

    // 创建画布
    const graph = new Graph({
      container: dom,
      scroller: true,
      width: 1920, // 画布宽度，默认使用容器宽度。
      height: 820, // 画布高度，默认使用容器高度
      autoResize: false, // 是否监听容器大小改变，并自动更新画布大小。
      interacting: false, // 定制节点和边的交互行为。
      panning: true, // 画布是否可以拖拽平移，默认禁用
      mousewheel: {
        // 鼠标滚轮缩放，默认禁用
        enabled: true,
        modifiers: ['ctrl', 'meta'],
        zoomAtMousePosition: false,
      },
      background: {
        color: '#fffbe6', // 设置画布背景颜色
      },
      grid: {
        size: 10, // 网格大小 10px
        visible: true, // 渲染网格背景
      },
    })

    // 自动布局
    function layout() {
      const nodes: any = graph.getNodes()
      const edges: any = graph.getEdges()
      const g: any = new dagre.graphlib.Graph()
      g.setGraph({ rankdir: dir, nodesep: 16, ranksep: 50 })
      g.setDefaultEdgeLabel(() => ({}))

      const width = 260
      const height = 120
      nodes.forEach((node: Record<string, any>) => {
        g.setNode(node.id, { width, height })
      })

      edges.forEach((edge: Record<string, any>) => {
        const source = edge.getSource()
        const target = edge.getTarget()
        g.setEdge(source.cell, target.cell)
      })

      dagre.layout(g)

      graph.freeze()

      g.nodes().forEach((id: string) => {
        const node = graph.getCell(id) as Node
        if (node) {
          const pos = g.node(id)
          node.position(pos.x, pos.y)
        }
      })

      edges.forEach((edge: Record<string, any>) => {
        const source = edge.getSourceNode()
        const target = edge.getTargetNode()
        const sourceBBox = source.getBBox()
        const targetBBox = target.getBBox()

        console.log(sourceBBox, targetBBox)
        if ((dir === 'LR' || dir === 'RL') && sourceBBox.y !== targetBBox.y) {
          const gap = dir === 'LR' ? targetBBox.x - sourceBBox.x - sourceBBox.width : -sourceBBox.x + targetBBox.x + targetBBox.width
          const fix = dir === 'LR' ? sourceBBox.width : 0
          const x = sourceBBox.x + fix + gap / 2
          edge.setVertices([
            { x, y: sourceBBox.center.y },
            { x, y: targetBBox.center.y },
          ])
        } else if ((dir === 'TB' || dir === 'BT') && sourceBBox.x !== targetBBox.x) {
          const gap = dir === 'TB' ? targetBBox.y - sourceBBox.y - sourceBBox.height : -sourceBBox.y + targetBBox.y + targetBBox.height
          const fix = dir === 'TB' ? sourceBBox.height : 0
          const y = sourceBBox.y + fix + gap / 2
          edge.setVertices([
            { x: sourceBBox.center.x, y },
            { x: targetBBox.center.x, y },
          ])
        } else {
          edge.setVertices([])
        }
      })
      graph.unfreeze()
    }

    function createNode(item: Record<string, any>) {
      if (item['type'] === 'yzwyhlist') {
        return graph.createNode({
          id: item['id'],
          data: item,
          shape: 'html',
          html: () => {
            const container: HTMLElement = document.createElement('div')
            container.style.borderRadius = '4px'
            container.style.minHeight = '120px'
            container.style.width = '260px'
            container.style.transform = 'translateX(-130px)'
            container.style.display = 'flex'
            container.style.flexDirection = 'column'
            container.style.alignItems = 'center'
            container.style.border = '2px solid #f07d2a'
            container.style.paddingBottom = '30px'

            const title: HTMLElement = document.createElement('div')
            title.style.fontWeight = 'bold'
            title.style.height = '45px'
            title.style.width = '100%'
            title.style.textAlign = 'center'
            title.style.lineHeight = '45px'
            title.style.color = '#000'
            title.innerText = item['title']
            container.appendChild(title)

            const datalist = item['list']
            if (Array.isArray(datalist) && datalist.length > 0) {
              datalist.map((oneObj: Record<string, any>) => {
                const list = document.createElement('div')
                const label = document.createElement('div')
                label.style.paddingBottom = '3px'
                label.innerText = oneObj['title']
                const namephone: HTMLElement = document.createElement('div')
                namephone.innerText = oneObj['name'] + oneObj['phone']

                list.style.display = 'flex'
                list.style.flexDirection = 'column'
                list.style.alignItems = 'center'
                list.style.padding = '5px 0'

                list.appendChild(label)
                list.appendChild(namephone)

                container.appendChild(list)
              })
            }
            return container
          },
        })
      }

      return graph.createNode({
        id: item['id'],
        data: item,
        shape: 'html',
        html: {
          render(node: any) {
            const data: Record<string, unknown> = node.getData()
            return `<div class="item-container ${item['type']}">
            <div class="title ${item['type']}">${data.title}</div>
            <div  class="box ${item['type']}">
              <div class="name-phone ${item['type']}">${data.name}  ${data.phone}</div>
              <div class="infos ${item['type']}">${data.desc}</div>
            </div>
        </div>`
          },
          shouldComponentUpdate(node: Record<string, any>) {
            return node.hasChanged('data') // 控制节点重新渲染
          },
        },
      })
    }

    function createEdge(source: any, target: any) {
      return graph.createEdge({
        shape: 'org-edge',
        source: { cell: source },
        target: { cell: target },
      })
    }

    const nodes: any = []
    const edges: any = []
    if (Array.isArray(data) && data.length > 0) {
      for (let i = 0; i < data.length; i++) {
        const itemObj = data[i]
        nodes.push(createNode(itemObj))
        if (itemObj['pid'] != 0) {
          edges.push(createEdge(itemObj['id'], itemObj['pid']))
        }
      }
    }
    graph.resetCells([...nodes, ...edges])
    layout()
    return graph
  }
}

export default DBX6
